package trim.common.sm;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import trim.common.inputdata.FormatOrder;
import trim.common.Material;
import trim.common.inputdata.MaterialStock;
import trim.common.inputdata.InputData;
import trim.common.utils.Utils;

/**
 * SimpleTrimSMData.java
 * Простейшая реализация интерфейса {@link ITrimSMData}
 *
 * Created on 13.11.2008 22:09:45
 * @author Дмитрий
 */
public class SimpleTrimSMData implements ITrimSMData
{

  protected InputData inputData;
  protected double[][] X;
  protected double[][] X1;
  protected double[] Res;
  protected double[] V;
  protected int n;
  protected int maxt;
  protected double mint;
  protected int KnifeCount;
  protected int[] C;
  protected int S;
  protected Material material;

  protected SimpleTrimSMData()
  {
  }

  public SimpleTrimSMData(InputData inputData)
  {
    this.inputData=inputData.clone();
    FormatOrder[] fc=this.inputData.getFormatOrderList().toArray(new FormatOrder[0]);
    Arrays.sort(fc,new Comparator<FormatOrder>()
    {

      public int compare(FormatOrder o1,FormatOrder o2)
      {
        if(o1.getFormat().getLength()>o2.getFormat().getLength())
          return -1;
        else if(o1.getFormat().getLength()<o2.getFormat().getLength())
          return 1;
        else
          return 0;
      }
    });
    this.inputData.getFormatOrderList().clear();
    this.inputData.getFormatOrderList().addAll(Arrays.asList(fc));
    n=inputData.getFormatOrderList().size();
    getMemory();
    init(this.inputData);
  }

  protected void getMemory()
  {
    C=new int[n];
    X=new double[n][n];
    X1=new double[n][n];
    Res=new double[n];
    V=new double[n];
  }

  protected void init(InputData inputData)
  {
    Material m=inputData.getMaterialStockList().get(0).getMaterial();
    material=m;
    S=m.getLength()-m.getMinEdge()*2;
    mint=2*(m.getMaxEdge()-m.getMinEdge());
    maxt=m.getKnifeInterval();
    KnifeCount=m.getKnifeCount();

    int i=0;
    for(FormatOrder fc:inputData.getFormatOrderList())
      C[i++]=fc.getFormat().getLength();
    //заполнение начального решения
    for(i=0;i<n;i++)
    {
      for(int j=0;j<n;j++)
        if(i==j)
        {
          X[i][j]=1;//min(S/C[i],KnifeCount-1);
        //while(S-C[i]*X[i][i]<maxt&&S-C[i]*X[i][i]>mint)X[i][i]--;
        }else
          X[i][j]=0;
    }
    //начальная обратная матрица и результат
    for(i=0;i<n;i++)
    {
      for(int j=0;j<n;j++)
        if(i!=j)
          X1[i][j]=X[i][j];
        else
        {
          X1[i][j]=1.0/(double)X[i][j];
        //smData.X1[n][i]=smData.X1[i][j];
        }
    }
    //начальный результат
    //smData.SMRes[n]=-L[n];
    for(i=0;i<n;i++)
    {
      Res[i]=(double)inputData.getFormatOrderList().get(i).getCount()*X1[i][i];
    //smData.SMRes[n]+=smData.SMRes[i];
    }
    //вычисление вектора двойственных перменных
    //dualVars[n]=1[n]*X1[n,n]   [dualVars[M]=C[N']*a1[N',M]]
    for(i=0;i<n;i++)
      V[i]=X1[i][i];
  //smData.dualVars[n]=0;
  }

  @Override
  public List<FormatOrder> getFormatCountList()
  {
    return inputData.getFormatOrderList();
  }

  @Override
  public double[] getStartObjectiveFunction()
  {
    return Res;
  }

  @Override
  public double[][] getStartBaseMatrix()
  {
    return X;
  }

  @Override
  public double[][] getStartInverseMatrix()
  {
    return X1;
  }

  @Override
  public double[] getStartDualVariables()
  {
    return V;
  }

  @Override
  public int getProblemSize()
  {
    return inputData.getFormatOrderList().size();
  }

  @Override
  public SMColumn getBestColumn(double[] dualVars)
  {
    int[] r=Utils.getBestPattern_BB(C,dualVars,n,material,1.0);
    double rec=0.0;
    double col[]=new double[n];
    for(int i=0;i<n;i++)
    {
      rec+=dualVars[i]*r[i];
      col[i]=r[i];
    }
    return new SMColumn(rec-1,col);
  }

  @Override
  public List<MaterialStock> getMatrialCountList()
  {
    return inputData.getMaterialStockList();
  }
}
